# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
"""
Option Menu for setting options used in a game for any ui toolkit.
"""
__docformat__ = "restructuredtext en"
#n_ = lambda x: x
#_ = lambda x: x

import math
import tkinter.ttk

from . import constants as vcnst
from .dialog import Dialog
from .widget import Menu
from ._dlg_config import (SoundsDialog as _SoundsDialog,
                          PlayersDialog as _PlayersDialog,
                          TimeoutsDialog as _TimeoutsDialog,
                          ColorsDialog as _ColorsDialog,
                          FontsDialog as _FontsDialog,)
from .select import (CardsetChooser as _CardsetChooser,
                     TilesetChooser as _TilesetChooser,)
from ..gamelib import state
from ..packlib.data import CARD_DB
from ..packlib.info import CARDSET
from ..pysolaudio import AUDIO_DEV
from ..resourceng import TILE_DB
from ..settings import CONF_OPT, TITLE
from ..statdb import STAT_DB


class OptionMenuMixin(object):
    """
    Build the toolkit neutral part of the option  menu.
    """
    game = top = app = None

    def _get_option(self, key):
        """
        _get_option(key:str) -> Menu option value

        Subclass return value of a menu option.
        """
        raise NotImplementedError

    def _set_option(self, key, value):
        """
        _set_option(key:str, value:str) -> None

        Stub set value of a menu option.
        """
        raise NotImplementedError

    def set_state(self, *args):
        """
        set_state(state:bool, menu:Menu, index:int) -> None

        Stub enable/disable menu item on path by value given.
        """
        raise NotImplementedError

    def connect_game(self, game):
        """
        connect_game(self, game:Game) -> None

        Connect game tkVariables to value in Game object. Then call parent
        method update other tkVariables.
        """
        self._set_option('cardback', CARD_DB[CARD_DB.choice()]['backindex'])
        self.update_cardback_menu()

        self.top.bind('<<update_cardback_menu>>',
                      lambda e, c=True: self.update_cardback_menu())

        ancestor = super(OptionMenuMixin, self)
        if hasattr(ancestor, 'connect_game'):
            ancestor.connect_game(game)
    def _add_options_menu(self, menu):
        """
        _add_options_menu(menu:Menu) -> None

        Create the game options menu:
          - Player options... command
          - automate play menu
          - Assist level menu
          - Sound... command
          - Card size menu
          - Cardset... command
          - Table tile... command
          - Card background menu (updates after game connect)
          - Card view menu
          - Animations menu
          - Mouse menu
          - Fonts... command
          - Colors... command
          - Timeouts...command
          - Set theme menu
          - Toolbar menu
          - Statusbar menu
          - Demo logo command
          - Startup splash screen command
        """
        meta = self._meta_mkey
        menu.add_command(label=n_('&Player options...'),
                         command=self._config_player_options)
        self._add_automate_menu(Menu(menu, label=n_('&automate play')))
        self._add_support_menu(Menu(menu, label=n_('Assist &level')))
        menu.add_separator()
        menu.add_checkbutton(label=n_('&Sound...'),
                             variable=self._get_variable('sound'),
                             command=self._config_sound_options,
                             state=self._get_state(AUDIO_DEV.connected))
        self._add_cardscale_menu(Menu(menu, label=n_('Card si&ze')))
        menu.add_command(label=n_('Cards&et...'), accelerator=meta.format('E'),
                         command=self._choose_cardset)
        menu.add_command(label=n_('Table t&ile...'),
                         command=self._choose_tileset)
        Menu(menu, label=n_('Card &background'))  # updates after
        self._add_cardview_menu(Menu(menu, label=n_('Card &view')))
        self._add_animate_menu(Menu(menu, label=n_('A&nimations')))
        self._add_mouse_menu(Menu(menu, label=n_('&Mouse')))
        menu.add_separator()
        menu.add_command(label=n_('&Fonts...'),
                         command=self._config_font_options)
        menu.add_command(label=n_('&Colors...'),
                         command=self._config_color_options)
        menu.add_command(label=n_('Time&outs...'),
                         command=self._config_timeout_options)
        menu.add_separator()
        self._add_themes_menu(Menu(menu, label=n_('Set t&heme')))
        self._add_toolbar_menu(Menu(menu, label=n_('&Toolbar')))
        self._add_statusbar_menu(Menu(menu, label=n_('Stat&usbar')))
        menu.add_checkbutton(label=n_('&Demo logo'),
                             variable=self._get_variable('demo_logo'),
                             command=lambda k='demo_logo':
                                         self._update_option(k))
        menu.add_checkbutton(label=n_('Startup splash sc&reen'),
                             variable=self._get_variable('splashscreen'),
                             command=lambda k='splashscreen':
                                         self._update_option(k))

    def create_keybindings(self):
        """
        create_keybindings() -> None

        Bind Options menu related commands to a key or meta and key combo. Then
        call method next ancestor.
        """
        meta = self._meta_bkey
        self._bind_keypress(meta, 'e',
                            lambda e: self._choose_cardset())
        self._bind_keypress(meta, 'plus',
                            lambda e: self._increase_scale())
        self._bind_keypress(meta, 'equal',
                            lambda e: self._increase_scale())
        self._bind_keypress(meta, 'minus',
                            lambda e: self._decrease_scale())
        self._bind_keypress(meta, '0',
                            lambda e: self._update_scale_option())

        # undocumented
        self._bind_keypress(meta, 'b',
                            lambda e: self._next_cardback())
        self._bind_keypress(meta, 'i',
                            lambda e: self._next_tileset())
        self._bind_keypress(meta, 'p',
                            lambda e: self._config_player_options())

        ancestor = super(OptionMenuMixin, self)
        if hasattr(ancestor, 'create_keybindings'):
            ancestor.create_keybindings()

    def _add_automate_menu(self, menu):
        """
        _add_automate_menu(menu:Menu) -> None

        Create the game automate menu:
          - Auto face up command
          - Auto drop command
          - Auto deal command
          - Quick Play command
        """
        for keyname, label in [('autofaceup', n_('Auto &face up')),
                               ('autodrop', n_('A&uto drop')),
                               ('autodeal', n_('Auto &deal'))]:
            menu.add_checkbutton(label=label,
                                 variable=self._get_variable(keyname),
                                 command=lambda k=keyname:
                                             self._update_autoplay_option(k))

        menu.add_separator()

        menu.add_checkbutton(label=n_('&Quick play'),
                             variable=self._get_variable('quickplay'),
                             command=lambda k='quickplay':
                                         self._update_option(k))

    def _add_support_menu(self, menu):
        """
        _add_support_menu(menu:Menu) -> None

        Create the game support menu:
          - Enable undo command
          - Enable bookmarks command
          - Enable hint command
          - Enable shuffle command
          - Enable highlight piles command
          - Enable highlight cards command
          - Enable highlight same rank command
          - Highlight no matching command
          - Show removed tiles (in Mahjongg games) command
          - Show hint &arrow (in Shisen-Sho games) command
        """
        for keyname, label in [('undo', n_('Enable &undo')),
                            ('bookmarks', n_('Enable &bookmarks')),
                            ('hint', n_('Enable &hint')),
                            ('shuffle', n_('Enable shu&ffle')),
                            ('mark_piles', n_('Enable highlight p&iles')),
                            ('mark_cards', n_('Enable highlight &cards'))]:
            menu.add_checkbutton(label=label,
                                 variable=self._get_variable(keyname),
                                 command=lambda k=keyname:
                                             self._update_menu_option(k))

        menu.add_checkbutton(label=n_('Enable highlight same &rank'),
                        variable=self._get_variable('mark_same'),
                        command=lambda k='mark_same':
                                    self._update_option(k))
        menu.add_checkbutton(label=n_('Highlight &no matching'),
                        variable=self._get_variable('mark_none'),
                        command=lambda k='mark_none':
                                    self._update_option(k))

        menu.add_separator()

        menu.add_checkbutton(
                        label=n_('&Show removed tiles (Mahjongg games)'),
                        variable=self._get_variable('mahjongg_show_removed'),
                        command=lambda k='mahjongg_show_removed':
                                    self._update_game_option(k))
        menu.add_checkbutton(
                        label=n_('Show hint &arrow (Shisen-Sho games)'),
                        variable=self._get_variable('shisen_show_hint'),
                        command=lambda k='shisen_show_hint':
                                    self._update_option(k))

    def _add_cardscale_menu(self, menu):
        """
        _add_cardscale_menu(menu:Menu) -> None

        Create the game card scale menu:
          - Increase the card size command
          - Decrease the card size command
          - Auto scaling command
        """
        meta = self._meta_mkey
        menu.add_command(label=n_('&Increase the card size'),
                         accelerator=meta.format('+'),
                         command=self._increase_scale)
        menu.add_command(label=n_('&Decrease the card size'),
                         accelerator=meta.format('-'),
                         command=self._decrease_scale)
        menu.add_checkbutton(label=n_('&Auto scaling'),
                             variable=self._get_variable('scale_auto'),
                             accelerator=meta.format('0'),
                             command=self._update_scale_option)

    def _add_cardview_menu(self, menu):
        """
        _add_cardview_menu(menu:Menu) -> None

        Create the game card view menu:
          - Card shadow command
          - Shade legal moves command
          - Negative cards bottom command
          - Shrink face-down cards command
          - Shade filled stacks command
        """
        menu.add_checkbutton(label=n_('Card shado&w'),
                            variable=self._get_variable('animate_shadow'),
                            command=lambda k='animate_shadow':
                                        self._update_option(k))
        menu.add_checkbutton(label=n_('Shade &legal moves'),
                            variable=self._get_variable('drag_shade'),
                            command=lambda k='drag_shade':
                                        self._update_option(k))
        for keyname, label in [
                           ('pile_bottom', n_('&Negative cards bottom')),
                           ('pile_shrink', n_('Shrink face-down cards')),
                           ('mark_filled', n_('Shade &filled stacks'))]:
            menu.add_checkbutton(label=label,
                                variable=self._get_variable(keyname),
                                command=lambda k=keyname:
                                            self._update_game_option(k))

    def _add_animate_menu(self, menu):
        """
        _add_animate_menu(menu:Menu) -> None

        Create the game animation menu:
          - None command
          - Very fast command
          - Fast command
          - Medium
          - Slow command
          - Very slow
          - Redeal animation
          - Winning animation
        """
        for value, label in enumerate([n_('&None'), n_('&Very fast'),
                                       n_('&Fast'), n_('&Medium'), n_('&Slow'),
                                       n_('V&ery slow')]):
            menu.add_radiobutton(label=label, value=value,
                                 variable=self._get_variable('animate_speed'),
                                 command=lambda k='animate_speed':
                                             self._update_option(k))

        menu.add_separator()

        menu.add_checkbutton(label=n_('&Redeal animation'),
                             variable=self._get_variable('animate_redeal'),
                             command=lambda k='animate_redeal':
                                         self._update_option(k))
        menu.add_checkbutton(label=n_('&Winning animation'),
                             state=self._get_state(True),
                             variable=self._get_variable('animate_win'),
                             command=lambda k='animate_win':
                                         self._update_option(k))

    def _add_mouse_menu(self, menu):
        """
        _add_mouse_menu(menu:Menu) -> None

        Create the game mouse menu:
          - Drag-and-Drop command
          - Point-and-Click command
          - Sticky mouse command
        """
        for value, label in [('drag-n-drop', n_('&Drag-and-Drop')),
                             ('point-n-click', n_('&Point-and-Click')),
                             ('sticky-mouse', n_('&Sticky mouse'))]:
            menu.add_radiobutton(label=label, value=value,
                                 variable=self._get_variable('mouse_type'),
                                 command=lambda k='mouse_type':
                                             self._update_option(k))

        menu.add_separator()

        menu.add_checkbutton(label=n_('Use mouse for undo/redo'),
                             variable=self._get_variable('mouse_undo'),
                             command=lambda k='mouse_undo':
                                         self._update_option(k))

    def _add_statusbar_menu(self, menu):
        """
        _add_statusbar_menu(menu:Menu) -> None

        Create the game status and help bar menu:
          - Show statusbar command
          - Show &number of cards command
          - Show &help bar command
        """
        menu.add_checkbutton(label=n_('Show &statusbar'),
                             variable=self._get_variable('statusbar'),
                             command=lambda k='statusbar':
                                         self._config_statusbar_place(k))
        menu.add_checkbutton(label=n_('Show &number of cards'),
                             variable=self._get_variable('statusbar_cards'),
                             command=lambda k='statusbar_cards':
                                         self._update_option(k))
        menu.add_checkbutton(label=n_('Show &help bar'),
                             variable=self._get_variable('helpbar'),
                             command=lambda k='helpbar':
                                         self._config_statusbar_place(k))

    def _add_themes_menu(self, menu):
        """
        _add_themes_menu(menu:Menu) -> None

        Create the game themes menu:
          - Default command
          - Classic command
          - Revitalized command
          - Windows native command
          - XP Native command
          - Aqua command
          - ... command (other ttk.Style available)
        """
        all_themes = list(tkinter.ttk.Style(self.top).theme_names())
        all_themes.sort()

        labels = {'default': n_('Default'),
                  'classic': n_('Classic'),
                  'alt': n_('Revitalized'),
                  'winnative': n_('Windows native'),
                  'xpnative': n_('XP Native'),
                  'aqua': n_('Aqua')}

        for theme in all_themes:
            menu.add_radiobutton(label=labels.get(theme) if theme in labels
                                           else theme.capitalize(),
                                variable=self._get_variable('wm_theme'),
                                value=theme, command=self._config_theme_options)

    def _add_toolbar_menu(self, menu):
        """
        _add_toolbar_menu(menu:Menu) -> None

        Create the game toolbar menu:
          - Compound submenu
            - ... command (label/image placements available)
          - Hide command
          - Top command
          - Bottom command
          - Left command
          - Right command
        """
        submenu = Menu(menu, label=n_('Compound'))
        for value, label in ((vcnst.NONE, n_('Icons only'),),
                             (vcnst.TOP, n_('Text below icons'),),
                             (vcnst.LEFT, n_('Text beside icons'),),
                             ('text', n_('Text only'),),):
            submenu.add_radiobutton(label=label, value=value,
                        variable=self._get_variable('toolbar_compound'),
                        command=self._config_toolbar_labels)

        menu.add_separator()

        for value, label in enumerate([n_('Hide'), n_('Top'), n_('Bottom'),
                                       n_('Left'), n_('Right')]):
            menu.add_radiobutton(label=label, value=value,
                                 variable=self._get_option('toolbar'),
                                 command=self._config_toolbar_place)

        menu.add_separator()

        submenu = Menu(menu, label=n_('Visible buttons'))
        for widget in list(CONF_OPT['toolbar_vars'].keys()):
            submenu.add_checkbutton(label=_(widget.capitalize()),
                               variable=self._get_variable('toolbar_{}'.format(
                                                                       widget)),
                               command=lambda w=widget:
                                           self._config_toolbar_widget(w))

    @state.game_connect
    def update_cardback_menu(self):
        """
        update_cardback_menu() -> None

        Update the game cardback menu. Sets menu with menu sized images of
        available cardbacks for chosen cardset.
        """
        submenu = self._get_path('.menubar.options.cardbackground')[2]

        # delete all entries
        submenu.delete(0, 'last')

        # insert new cardbacks
        mbacks = self.game.images._back
        cbreak = int(math.ceil(math.sqrt(len(mbacks))))

        back = self.__card_backs = []
        for index, bg_image in enumerate(mbacks):
            back.append(bg_image.image.menu_image)  # prevent menu_image gc
            submenu.add_radiobutton(label=bg_image.name, image=back[index],
                                variable=self._get_variable('cardback'),
                                value=index, command=self._update_cardback,
                                columnbreak=index > 0 and (index % cbreak) == 0,
                                indicatoron=False, hidemargin=False)

    @state.game_connect
    def update_menu_state(self):
        """
        update_menu_state() -> None

        Update menu item enable state.
        """
        self.set_state('autofaceup', 'options.automateplay.autofaceup')
        self.set_state('autodrop', 'options.automateplay.autodrop')
        self.set_state('autodeal', 'options.automateplay.autodeal')
        self.set_state('quickplay', 'options.automateplay.quickplay')

        ancestor = super(OptionMenuMixin, self)
        if hasattr(ancestor, 'update_menu_state'):
            ancestor.update_menu_state()

    @state.cancel_drag(False)
    def _update_option(self, key):
        """
        _update_option(key:str) -> None

        Update conf option for key.
        """
        CONF_OPT[key] = self._get_option(key)

    @state.cancel_drag(True)
    def _update_autoplay_option(self, key):
        """
        _update_autoplay_option(key:str) -> None

        For autoplay option support.

        Update conf option for key. When its current value call game.auto_play.
        """
        CONF_OPT[key] = self._get_option(key)
        self.game.auto_play()

    @state.cancel_drag(False)
    def _update_menu_option(self, key):
        """
        _update_menu_option(key:str) -> None

        For visual assist option support.

        Update conf option for key. Then call update menus method.
        """
        CONF_OPT[key] = self._get_option(key)
        self.update_menu_state()

    @state.cancel_drag(False)
    def _update_game_option(self, key):
        """
        _update_game_option(key:str) -> None

        For game option support.

        Update conf option for key. Bookmark and refresh game to finish update.
        """
        CONF_OPT[key] = self._get_option(key)
        self.game.quit(mode='mark')

    @state.cancel_drag(False)
    def _config_statusbar_place(self, key):
        """
        _config_statusbar_place(key:str) -> None

        For status option support.

        Update conf option for key when bar exists. Call bar show method to
        finish update.
        """
        from .console import STATUS_BAR, ASSIST_BAR
        shbar = {'statusbar': STATUS_BAR,
               'helpbar': ASSIST_BAR}.get(key)
        if not shbar:
            return
        CONF_OPT[key] = self._get_option(key)
        if shbar.show(show=CONF_OPT[key], resize=True):
            self.top.update_idletasks()

    def _update_geometry_options(self):
        """
        _update_geometry_options() -> None

        For card scale option support.

        Update conf option for game geometry after card scaling.
        """
        game, canvas = self.game, self.game.canvas
        CONF_OPT['wm_geometry'] = (canvas.winfo_width(), canvas.winfo_height(),)
        game._view_resize()
        game._update_geomety()

    @state.cancel_drag(True)
    def _increase_scale(self):
        """
        _increase_scale() -> None

        For card scale option support.

        Update conf option after card scale increase. Cards may scale 2x size.
        Calls update canvas geometry to finish update.
        """
        if any(s >= 2 for s in CONF_OPT['scale']):  # Max 2x
            return
        CONF_OPT['scale'][0] += 0.1
        CONF_OPT['scale'][1] += 0.1
        self._set_option('scale_auto', False)
        CONF_OPT['scale_auto'] = self._get_option('scale_auto')
        self._update_geometry_options()

    @state.cancel_drag(True)
    def _decrease_scale(self):
        """
        _decrease_scale() -> None

        For card scale option support.

        Update conf option after card scale increase. Cards may scale 50% size.
        Calls update canvas geometry to finish update.
        """
        if any(CONF_OPT[k] <= 0.5 for k in ['scale_x', 'scale_y']):  # Min 1/2x
            return
        CONF_OPT['scale_x'] -= 0.1
        CONF_OPT['scale_y'] -= 0.1
        self._set_option('scale_auto', False)
        CONF_OPT['scale_auto'] = self._get_option('scale_auto')
        self._update_geometry_options()

    @state.cancel_drag(True)
    def _update_scale_option(self):
        """
        _decrease_scale() -> None

        For card scale option support.

        Update conf option after card scale set auto. Calls update canvas
        geometry to finish update.
        """
        self._set_option('scale_auto', not CONF_OPT['scale_auto'])
        CONF_OPT['scale_auto'] = self._get_option('scale_auto')
        self._update_geometry_options()

    def _open_cardset_chooser(self, choice):
        """
        _open_cardset_chooser(choice:int) -> bool

        For card pack option support.

        Call Cardset chooser to select a new card pack and/or rescale cards.
        Update menu options after chooser and handle possible image resize.
        """
        if _CardsetChooser is None:
            return
        choice = choice
        old_opt = [CONF_OPT[k] for k in ['scale', 'scale_auto', 'scale_keep']]
        chooser = _CardsetChooser(self.top, app=self.app, choice=choice,
                                 title=_('{0} Chooser').format(CARDSET))

        if not chooser.result:
            return False

        self._set_option('scale_auto', CONF_OPT['scale_auto'])

        new_opt = [CONF_OPT[k] for k in ['scale', 'scale_auto', 'scale_keep']]

        if choice == CARD_DB.choice() and not old_opt != new_opt:
            return False

        if not CONF_OPT['scale_auto']:
            self.game.images.resize(*CONF_OPT['scale'])
        return True

    @state.cancel_drag(True)
    def _choose_cardset(self):
        """
        _choose_cardset(event=None) -> None

        For card pack option support.

        Call open cardset chooser to update card pack choice. If changed,
        bookmark and refresh game to finish update.
        """
        if self._open_cardset_chooser(CARD_DB.choice()):
            self.game.quit(mode='mark')

    def _update_cardback(self, index=None):
        """
        _update_cardback(index:int=None) -> None

        For card back option support.

        Update card back choice from index or current menu option.
        """
        index = index or self._get_option('cardback')
        game = self.game
        old_index = game.images.cs['backindex']
        game.images.cs.update_back(index=index)
        if game.images.cs['backindex'] == old_index:
            return
        CARD_DB.update_imageset()
        image = game.images.back
        for card in game.cards:
            card.update_back(image=image)
        self.game.canvas.update_idletasks()

    @state.cancel_drag(False)
    def _next_cardback(self):
        """
        _next_cardback() -> None

        For card pack option support.

        Increase card back index choice wrap down if greater then backs
        available before call update card back.
        """
        num_backs = len(self.game.images.cs['backnames'])
        self._update_cardback((self._get_option('cardback') + 1) % num_backs)

    def __update_tileset_options(self, old_choice, new_choice):
        """
        __update_tileset_options(old_choice:int, new_choice:int) -> None

        For background option support.

        Update background choice providing rollback for problems.
        """
        if self.app.set_background():
            TILE_DB.choice(new_choice)
            self._set_option('tabletile', new_choice)
        else:
            TILE_DB.choice(old_choice)
            self._set_option('tabletile', old_choice)

    @state.cancel_drag(False)
    def _next_tileset(self):
        """
        __increase_background() -> None

        For background option support.

        Increase background choice index wrap down if greater then backs
        available before call update card back.
        """
        backgrounds = len(TILE_DB)
        if backgrounds >= 2:
            old_choice = TILE_DB.choice()
            new_choice = (self._get_option('tabletile') + 1) % backgrounds
            self.__update_tileset_options(old_choice, new_choice)

    @state.cancel_drag(False)
    def _choose_tileset(self):
        """
        _choose_tileset(event=None) -> None

        For background option support.

        Call TilesetChooser to choose a background then call update card back
        with choice.
        """
        if _TilesetChooser is None:
            return
        choice = TILE_DB.choice()
        chooser = _TilesetChooser(self.top, _('Select table background'),
                                 app=self.app, choice=choice)
        if chooser.result:
            self.__update_tileset_options(choice, TILE_DB.choice())

    @state.cancel_drag(False)
    def _config_toolbar_place(self):
        """
        _config_toolbar_place() -> None

        For toolbar option support.

        Update conf option then config toolbar docking side with new options.
        """
        from .console import TOOL_BAR

        side = self._get_option('toolbar')
        if TOOL_BAR.show(side, resize=True):
            self.top.update_idletasks()

    @state.cancel_drag(False)
    def _config_toolbar_labels(self):
        """
        _config_toolbar_labels() -> None

        For toolbar option support.

        Update conf option then config toolbar text/image place with new option.
        """
        from .console import TOOL_BAR

        compound = self._get_option('toolbar_compound')
        if TOOL_BAR.update_region_image(compound=compound):
            TOOL_BAR.update_region_text(player=CONF_OPT['player'])
            self.top.update_idletasks()

    @state.cancel_drag(False)
    def _config_toolbar_widget(self, widget):
        """
        _config_toolbar_widget() -> None

        For toolbar option support.

        Update conf option then config toolbar widget with new option.
        """
        from .console import TOOL_BAR

        show = self._get_option('toolbar_{}'.format(widget))
        if TOOL_BAR.show_region(widget, show):
            self.top.update_idletasks()

    @state.cancel_drag(False)
    def _config_player_options(self):
        """
        _config_player_options() -> None

        For config support.

        Stub to change player options.
        """
        from .console import update_console_text

        if _PlayersDialog is None:
            return
        player = CONF_OPT['player']
        _PlayersDialog(self.top)
        if player != CONF_OPT['player']:
            update_console(
                       stats=STAT_DB.basic(CONF_OPT['player'], self.game['id']))

    @state.cancel_drag(False)
    def _config_color_options(self):
        """
        _config_color_options() -> None

        For config support.

        Config text color options.
        """
        if _ColorsDialog is None:
            return
        text_color = CONF_OPT['colors']['text']
        _ColorsDialog(self.top)
        if text_color != CONF_OPT['colors']['text']:
            self.app.set_background(force=True)

    @state.cancel_drag(False)
    def _config_font_options(self):
        """
        _config_font_options() -> None

        For config support.

        Config font options.
        """
        if _FontsDialog is None:
            return
        game = self.game
        config = _FontsDialog(self.top)
        if config.status == True:
            game.quit(mode='mark')

    @state.cancel_drag(False)
    def _config_timeout_options(self):
        """
        _config_timeout_options() -> None

        For config support.

        Config timeout options.
        """
        if _TimeoutsDialog is not None:
            _TimeoutsDialog(self.top)

    @state.cancel_drag(False)
    def _config_sound_options(self):
        """
        _config_sound_options() -> None

        For config support.

        Stub to change sound options.
        """
        if _SoundsDialog is not None:
            _SoundsDialog(self.top)
            self._set_option('sound', CONF_OPT['sound'])

    def _config_theme_options(self):
        """
        _config_theme_options() -> None

        For config support.

        Stub to change ui theme options.
        """
        CONF_OPT['wm_theme'] = self._get_option('wm_theme')
        Dialog.warning(text=_('This settings will take effect the next time you'
                              'restart {}').format(TITLE))